﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using ShevaEngine.Core.Interfaces;
using ShevaEngine.Core.Modules.Input;

namespace ShevaEngine.Core.Modules.Graphics.Cameras
{
    /// <summary>
    /// Fly camera controller.
    /// </summary>
    public class FlyCameraController : IUpdateAble
    {
        /// <summary>Camera.</summary>
        private Camera Camera;
        /// <summary>Rotation.</summary>
        private Quaternion Rotation;
        /// <summary>Previous mose position.</summary>
        private Vector2 PreviousMousePosition;
        /// <summary>Camera speed.</summary>
        public float CameraSpeed = 1000;
        /// <summary>Camera rotation.</summary>
        private Vector2 CameraRot;
        /// <summary>Mouse position.</summary>
        private Vector2 MousePos;
        /// <summary>Camera position.</summary>
        private Vector3 CameraPosition = Vector3.Zero;
        /// <summary>Camera target.</summary>
        private Vector3 CameraTarget = Vector3.Zero;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="camera"></param>
        public FlyCameraController(Camera camera)
        {
            this.Camera = camera;

            this.Rotation = Quaternion.Identity;
            this.PreviousMousePosition = Vector2.Zero;

            InputManager.Instance.Mouse.OnMouseMove += new OnMouseMoveDelegate(Mouse_OnMouseMove);
        }

        /// <summary>
        /// Mouse moved event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="position"></param>
        void Mouse_OnMouseMove(object sender, Vector2 position)
        {
            if (this.PreviousMousePosition == Vector2.Zero)
                this.PreviousMousePosition = position;

            this.MousePos += new Vector2(position.X - this.PreviousMousePosition.X, position.Y - this.PreviousMousePosition.Y);

            this.PreviousMousePosition = position;
        }       

        /// <summary>
        /// Method Update().
        /// </summary>
        /// <param name="time"></param>
        public void Update(GameTime time)
        {
            float TimeDelta = (float)time.ElapsedGameTime.TotalSeconds;

            Vector3 moveVector = Vector3.Zero;

            float MoveFactor = CameraSpeed * TimeDelta;
            
            if (InputManager.Instance.Keyboard.IsKeyDown(Keys.W))
                moveVector.Z -= MoveFactor;
            if (InputManager.Instance.Keyboard.IsKeyDown(Keys.S))
                moveVector.Z += MoveFactor;
            if (InputManager.Instance.Keyboard.IsKeyDown(Keys.A))
                moveVector.X -= MoveFactor;
            if (InputManager.Instance.Keyboard.IsKeyDown(Keys.D))
                moveVector.X += MoveFactor; 

            float MouseSensitivity = 1f;

            this.CameraRot -= new Vector2(
                (this.MousePos.Y * MouseSensitivity) * TimeDelta,
                (this.MousePos.X * MouseSensitivity) * TimeDelta);

            this.MousePos = Vector2.Zero;

            this.CameraRot.X = MathHelper.Clamp(this.CameraRot.X, MathHelper.ToRadians(-90), MathHelper.ToRadians(+90));
            //Mouse.SetPosition(device.Viewport.Width / 2, device.Viewport.Height / 2); // vycentruje myš.

            Matrix cameraRotationMatrix = Matrix.CreateRotationX(this.CameraRot.X) * Matrix.CreateRotationY(this.CameraRot.Y);

            Vector3 TransformedCameraReference = Vector3.Transform(Vector3.Forward, cameraRotationMatrix);
            
            this.CameraPosition += Vector3.Transform(moveVector, cameraRotationMatrix);
            this.CameraTarget = TransformedCameraReference + CameraPosition;
            
            Vector3 CameraRotatedUpVector = Vector3.Transform(Vector3.Up, cameraRotationMatrix);

            this.Camera.ViewMatrix = Matrix.CreateLookAt(this.CameraPosition, CameraTarget, CameraRotatedUpVector);
        } 
    }
}
